#ifndef GRITC_SERVER_WORLD_HPP
#define GRITC_SERVER_WORLD_HPP

#include <sys/timeb.h>
#include <algorithm>
#include <map>

namespace gritc { namespace server {

	typedef unsigned long long time_type;

	time_type get_time()
	{
		timeb t;
		ftime(&t);

		time_type r = t.time;
		r *= 1000;
		r += t.millitm;
		return r;
	}

	template<class Traits> struct world
	{
		typedef Traits traits_type;
		typedef typename Traits::room_type room_type;
		typedef typename Traits::actor_type actor_type;
		typedef typename Traits::string_type string_type;
		typedef typename Traits::time_type time_type;
		typedef std::vector<room_type*> room_list;

		struct command
		{
			virtual ~command() {}
			virtual void handle
				(	world<Traits>&
				,	actor_type&
				,	typename string_type::iterator
				,	typename string_type::iterator ) = 0;
		};
		template<class F> struct commandv : command
		{
			F f;
			commandv(F & f_) : f(f_) {}
			virtual ~commandv() {}
			virtual void handle
				(	world<Traits>& w
				,	actor_type& a
				,	typename string_type::iterator b
				,	typename string_type::iterator e )
			{
				f(w,a,b,e);
			}
		};

		typedef std::map<string_type,command*> command_map;

		command_map commands_;
		command_map & commands() { return commands_; }

		room_list rooms_;
		room_list & rooms() { return rooms_; }

		time_type last_tick_;
		time_type last_tick() { return last_tick_; }
		void last_tick(const time_type t) { last_tick_ = t; }

		~world()
		{
			for(command_map::iterator i = commands_.begin(); i != commands_.end(); ++i)
				delete (*i).second;
		}
		template<class S, class F> world<Traits> & add_command(S & name, F & f) 
		{
			if(!commands_.insert(std::make_pair(name, new commandv<F>(f))).second)
				throw -1;
			return *this;
		}
	};

	struct do_text_
	{
		template<class World, class Actor, class Iterator>
		void operator()(World & world_, Actor & actor_, Iterator begin, Iterator end) const
		{
			typedef World::command_map Map;

			Iterator token = std::find(begin,end,' ');

			if(begin == end)
			{
				actor_.respond("error unknown command");
				return;
			}

			Map & map_ = world_.commands();
			Map::iterator i = map_.find(Map::key_type(begin, token));

			if(i == map_.end())
			{
				actor_.respond("error unknown command");
				return;
			}

			(*i).second->handle(world_, actor_, token, end);
		}
	} const do_text;

	struct tick_world_
	{
		template<class World> void operator ()(World & world_) const
		{
			typedef World::traits_type Traits;
			typedef World::room_list List;
			typedef Traits::tick_type Tick;
			typedef Traits::effect_pointer Pointer;

			Tick tick_(world_, world_.last_tick(), get_time());
			Pointer pointer_(new_effect(tick_));
			
			List & l = world_.rooms();
			List::iterator end = l.end();

			for(List::iterator i = l.begin(); i != end; ++i)
				tick_room(**i, tick_, pointer_);

			world_.last_tick(tick_.now());
		}
	} const tick_world;

}}

#endif